package org.fb.handler;

import org.apache.zookeeper.CreateMode;
import org.fb.bean.UserServiceBeanDefinition;
import org.fb.bean.UserServiceBeanFactory;
import org.fb.utils.ZkClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @author fanbo@imoran.net
 * @date 2021/2/24 7:19
 */
@Component
@EnableScheduling
public class ServerBalanceHandler {


    @Value("${spring.application.name:client}")
    public String clientName;

    private String rootNode = "/load-balance";

    /**
     * 记录服务端相应耗时
     */
    public static Map<String, Long> serverResponseTimeMap = new HashMap<>(2);

    /**
     * 记录每个服务端的最后一次响应时间，有效时间为5秒，5s内如果该服务端没有新的请求，响应时间清零或失效。
     * @return
     */
    public UserServiceBeanDefinition serverBalance() {
        ZkClient zkClient = new ZkClient();
        zkClient.init();

        List<UserServiceBeanDefinition> beanList = UserServiceBeanFactory.beanList;

        // 存储各个服务端的最后一次相应时间
        HashMap<String, Long> serverTimeMap = new HashMap<>(2);
        for (UserServiceBeanDefinition userServiceBeanDefinition : beanList) {
            String serverName = userServiceBeanDefinition.getServerName();
            // 查询服务端最后一次响应时间
            String path = rootNode + "/" + clientName + "/" + serverName;
            if (zkClient.checkExists(path)) {
                String time = zkClient.getData(path);
                serverTimeMap.put(serverName, Long.valueOf(time));
            } else {
                serverTimeMap.put(serverName, null);
            }
        }

        // 筛选响应时间最短的服务端
       if (serverTimeMap.containsValue(null)) {
            // 如果服务端响应时间存在空值，则随机选择一个服务端
            Random random = new Random();
            int index = random.nextInt(beanList.size());
            return beanList.get(index);
        }

        // 如果不存在空值，挑选耗时最短的服务端
        List<Map.Entry<String, Long>> list = new ArrayList<>(serverTimeMap.entrySet());
        // 按时间从小到大排序
        list.sort(Comparator.comparing(Map.Entry::getValue));
        String serverName = list.get(0).getKey();
        for (UserServiceBeanDefinition userServiceBeanDefinition : beanList) {
            if (userServiceBeanDefinition.getServerName().equals(serverName)) {
                return userServiceBeanDefinition;
            }
        }
        return null;
    }

    /**
     * 定时上报， 15s一次，便于演示
     */
    //@Scheduled(fixedRate = 15000)
    public void reportTiming() {
        String clientRoot = rootNode + "/" + clientName;
        /*
        zookeeper目录结果：
        /load-balance
            /client
                /rpc1 20ms
                /rpc2 25ms
        */
        System.out.println("定时上报开始");
        ZkClient zkClient = new ZkClient();
        zkClient.init();

        // 创建client根节点
        System.out.println("clientRoot: " + clientRoot);
        if (zkClient.checkExists(clientRoot)) {
            zkClient.deleteChildrenIfNeeded(clientRoot);
        }

        zkClient.createPersistentNode(clientRoot, null);

        for (Map.Entry<String, Long> entry : serverResponseTimeMap.entrySet()) {
            String serverName = entry.getKey();
            Long time = entry.getValue();
            System.out.println("定时上报服务端：" + serverName + ", 响应时间：" + time + "毫秒");

            String path = clientRoot + "/" + serverName;
            if (zkClient.checkExists(path)) {
                zkClient.delete(path);
            }
            zkClient.createPersistentNode(path, time.toString());
        }

        // 清除之前的记录
        serverResponseTimeMap.clear();
    }
}
